from types import SimpleNamespace
from typing import Union
from urllib.parse import quote

from src.config.parameter import Parameter
from src.handle.acquirer import Acquirer
from src.tools.retry import PrivateRetry


class Search(Acquirer):
    SEARCH = {
        "type": {
            "综合": 0,
            "视频": 1,
            "用户": 2,
            "直播": 3,
            "综合搜索": 0,
            "视频搜索": 1,
            "用户搜索": 2,
            "直播搜索": 3,
            "0": 0,
            "1": 1,
            "2": 2,
            "3": 3,
        },
        "type_text": {
            0: "综合搜索",
            1: "视频搜索",
            2: "用户搜索",
            3: "直播搜索",
        },
        "sort": {
            "综合排序": 0,
            "最新发布": 2,
            "最多点赞": 1,
            "0": 0,
            "1": 1,
            "2": 2,
        },
        "sort_text": {
            0: "综合排序",
            2: "最新发布",
            1: "最多点赞",
        },
        "publish_text": {
            0: "不限",
            1: "一天内",
            7: "一周内",
            182: "半年内",
        },
    }
    DATA_TYPE = {
        0: "search_general",
        1: "search_general",
        2: "search_user",
        3: "search_live"
    }
    search_params = (
        SimpleNamespace(
            api="https://www.douyin.com/aweme/v1/web/general/search/single/",
            count=15,
            channel="aweme_general",
            type="general",  # 综合搜索
        ),
        SimpleNamespace(
            api="https://www.douyin.com/aweme/v1/web/search/item/",
            count=20,
            channel="aweme_video_web",
            type="video",  # 视频
        ),
        SimpleNamespace(
            api="https://www.douyin.com/aweme/v1/web/discover/search/",
            count=12,
            channel="aweme_user_web",
            type="user",  # 用户
        ),
        SimpleNamespace(
            api="https://www.douyin.com/aweme/v1/web/live/search/",
            count=15,
            channel="aweme_live",
            type="live",  # 直播
        ),
    )

    def __init__(
            self,
            params: Parameter):
        self.keyword = ""
        self.tab = 0
        self.sort_type = 0
        self.publish_time = 0
        self.page = 1
        super().__init__(params)

    # 执行搜索
    def run(self, keyword: str, tab=0, page=1, sort_type=0, publish_time=0):
        self.keyword = keyword
        self.tab = tab
        self.page = page
        self.sort_type = sort_type
        self.publish_time = publish_time
        data = self.search_params[tab]
        self.PC_headers["Referer"] = (
            f"https://www.douyin.com/search/{quote(keyword)}?" f"source=switch_tab&type={data.type}")
        if tab in {2, 3}:
            deal = self._run_user_live
        elif tab in {0, 1}:
            deal = self._run_general
        else:
            raise ValueError
        deal(data, tab)
        self.page -= 1
        return self.response

    # 执行用户直播搜索
    def _run_user_live(self, data: SimpleNamespace, type_: int):
        params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "search_channel": data.channel,
            "keyword": self.keyword,
            "search_source": "switch_tab",
            "query_correct_type": "1",
            "is_filter_search": "0",
            "from_group_id": "",
            "offset": self.cursor,
            "count": 10 if self.cursor else data.count,
            "pc_client_type": "1",
            "version_code": "170400",
            "version_name": "17.4.0",
            "cookie_enabled": "true",
            "platform": "PC",
            "downlink": "10",
        }
        self.deal_url_params(params, 4 if self.cursor else 8)
        self._get_search_data(
            data.api,
            params,
            "user_list" if type_==2 else "data", finished=True)

    # 执行综合搜索
    def _run_general(self, data: SimpleNamespace, type_: int, *args):
        params = {
            "device_platform": "webapp",
            "aid": "6383",
            "channel": "channel_pc_web",
            "search_channel": data.channel,
            "sort_type": self.sort_type,
            "publish_time": self.publish_time,
            "keyword": self.keyword,
            "search_source": "tab_search",
            "query_correct_type": "1",
            "is_filter_search": {True: 1, False: 0}[any((self.sort_type, self.publish_time))],
            "from_group_id": "",
            "offset": self.cursor,
            "count": 10 if self.cursor else data.count,
            "pc_client_type": "1",
            "version_code": "170400" if type_ else "190600",
            "version_name": "17.4.0" if type_ else "19.6.0",
            "cookie_enabled": "true",
            "platform": "PC",
            "downlink": "10",
        }
        self.deal_url_params(params, 4 if self.cursor else 8)
        self._get_search_data(data.api, params, "data", finished=True)

    # 执行搜索请求
    @PrivateRetry.retry
    def _get_search_data(self, api: str, params: dict, key: str):
        if not (
                data := self.send_request(
                    api,
                    params=params,
                )):
            print("获取搜索数据失败")
            return False
        try:
            self.deal_item_data(data[key])
            self.cursor = data["cursor"]
            self.finished = not data["has_more"]
            return True
        except KeyError:
            print(f"搜索数据响应内容异常: {data}")
            self.finished = True
            return False

    def enter_search_criteria(self, keyword: str, _type="1", pages="1", sort_type="0", publish_time="0") -> Union[
        None, tuple, bool]:
        return self._verify_search_criteria(keyword, _type, pages, sort_type, publish_time)

    def _verify_search_criteria(
            self,
            keyword: str = None,
            type_: str = None,
            pages: str = None,
            sort: str = None,
            publish: str = None, *args) -> Union[tuple, bool]:
        if not keyword:
            return False
        if args:
            return True
        type_ = self.SEARCH["type"].get(type_, 0)
        # type_text = self.SEARCH["type_text"][type_]
        pages = self._extract_integer(pages)
        sort = self.SEARCH["sort"].get(sort, 0)
        # sort_text = self.SEARCH["sort_text"][sort]
        publish = int(publish) if publish in {"0", "1", "7", "182"} else 0
        # publish_text = self.SEARCH["publish_text"][publish]
        return keyword, type_, pages, sort, publish
